package com.wyg.demo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.wyg.demo.common.utils.SpringUtil;
import com.wyg.demo.domain.ExcelData;
import com.wyg.demo.domain.vo.ExcelDataVo;
import com.wyg.demo.exception.ServiceException;
import com.wyg.demo.listener.ExcelDataListener;
import com.wyg.demo.mapper.ExcelDataMapper;
import com.wyg.demo.service.ExcelDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author ygWen
 * @Description: ExcelData 业务类
 * @date 2022/1/1
 */
@Slf4j
@Service
public class ExcelDataServiceImpl implements ExcelDataService {
    
    @Autowired
    private ExcelDataMapper excelDataMapper;

    /**
     * excel表格上传的路径
     */
    @Value("${deposeFilesDir}")
    private String deposeFilesDir;
    
    /**
     * 下载导出数据后的excel文件的源路径
     */
    @Value("${downloadPath}")
    private String downloadPath;
    
    /**
     * excel模板文件全路径
     */
    @Value("${templateExcelPath}")
    private String templateExcelPath;

    /**
     * 保存数据到数据库
     * @param list 数据集合
     */
    @Override
    public void save(List<ExcelData> list) {
        excelDataMapper.save(list);
    }

    /**
     * 读取excel文件中的数据
     * @param filePath excel文件全路径
     */
    @Override
    public void excelRead(String filePath) {
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(filePath, ExcelData.class, new ExcelDataListener(SpringUtil.getBean(this.getClass())))
                .sheet().doRead();
    }

    /**
     * 上传excel文件到服务器指定路径下
     * @param file excel文件
     * @return 文件的全路径名字(含路径、文件名以及后缀)
     */
    @Override
    public String fileUpload(MultipartFile file) throws IOException {
        // 获取附件原名(有的浏览器如chrome获取到的是最基本的含 后缀的文件名,如myImage.png)
        // 获取附件原名(有的浏览器如ie获取到的是含整个路径的含后缀的文件名，如C:\\Users\\images\\myImage.png)
        String fileName = file.getOriginalFilename();
        //获取文件后缀名
        assert fileName != null;
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        if (!("xlsx".equals(suffix) || "xls".equals(suffix))) {
            throw new ServiceException("上传的文件必须是以.xlsx或者.xls为后缀的excel文件！");
        }
        // 如果是获取的含有路径的文件名，那么截取掉多余的，只剩下文件名和后缀名
        String separator = File.separator;
        int index = fileName.lastIndexOf(separator);
        if (index > 0) {
            fileName = fileName.substring(index + 1);
        }
        // 以下部分，目的为修改文件名，防止上传上来的文件名与已有的文件名重复
        // 当文件有后缀名时
        if (fileName.contains(".")) {
            // split()中放正则表达式; 转义字符"\\."代表 "."
            String[] fileNameSplitArray = fileName.split("\\.");
            // 加上时间戳,防止附件重名覆盖原文件
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmssSSS");
            fileName = fileNameSplitArray[0] + "_" + simpleDateFormat.format(new Date()) + "." + fileNameSplitArray[1];
        }
        // 根据文件的全路径名字(含路径、后缀),new一个File对象dest
        File dest = new File(deposeFilesDir + fileName);
        // 如果该文件的上级文件夹不存在，则创建该文件的上级文件夹及其祖辈级文件夹;
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        // 将获取到的附件file,transferTo写入到指定的位置(即:创建dest时，指定的路径)
        file.transferTo(dest);
        // 服务器上文件的全路径名字(含路径、后缀)
        return deposeFilesDir + fileName;
    }

    /**
     * 查询数据库中的数据（可按条件查询）
     * @param excelDataVo excelDataVo类
     * @return 数据列表
     */
    @Override
    public List<ExcelData> selectDataList(ExcelDataVo excelDataVo) {
        return excelDataMapper.selectDataList(excelDataVo);
    }

    /**
     * 将数据写入excel
     * @param list 数据列表
     * @return 文件名
     */
    @Override
    public String excelSimpleWrite(List<ExcelData> list) throws IOException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmssSSS");
        String fileName = downloadPath + "excelData" + "_" + simpleDateFormat.format(new Date()) + ".xlsx";
        File file = new File(fileName);
        if (!file.exists()) {
            file.createNewFile();
        }
        EasyExcel.write(fileName, ExcelData.class)
                .sheet("数据")
                .doWrite(list);
        return fileName;
    }

    /**
     * 将excel文件下载到本地
     * @param response 响应
     * @param fileName 服务器上文件名称
     */
    @Override
    public void downloadExcel(HttpServletResponse response, String fileName) throws IOException {
        File file = new File(fileName);
        // 获取文件名称
        String filename = file.getName();
        response.reset();
        // 先去掉文件名称中的空格,然后转换编码格式为utf-8,保证不出现乱码,这个文件名称用于浏览器的下载框中自动显示的文件名
        response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.replaceAll(" ", "").getBytes("utf-8"),"iso8859-1"));
        response.addHeader("Content-Length", "" + file.length());
        response.setContentType("application/msexcel");
        // 输入流
        InputStream fis = new BufferedInputStream(new FileInputStream(fileName));
        //输出流
        OutputStream os = new BufferedOutputStream(response.getOutputStream());
        int bytes = 0;
        byte[] bufferOut = new byte[1024];
        while ((bytes = fis.read(bufferOut)) != -1) {
            os.write(bufferOut, 0, bytes);
        }
        fis.close();
        os.flush();
        os.close();
    }

    /**
     * 将excel模板文件下载到本地
     */
    @Override
    public void downloadExcelTemplate(HttpServletResponse response) throws IOException {
        downloadExcel(response, templateExcelPath);
    }
}
